package benders_decomposition;

/*-----------------------------------

Master Problem:

    min 7(y1 + y2 + y3 + y4 + y5) + t

    s.t.    t >= 0 
            y = 0 or 1

-----------------------------------*/

import gurobi.GRB;
import gurobi.GRBEnv;
import gurobi.GRBException;
import gurobi.GRBLinExpr;
import gurobi.GRBModel;
import gurobi.GRBVar;

import Jama.Matrix;

public class MasterProblem {

    private GRBEnv env;
    private GRBModel model;
    private GRBVar[] x;
    private GRBVar t;

    public int xNum = 5;
    public Matrix solutions;
    public double objVal;
    public double tValue;

    MasterProblem() {
        try {
            env = new GRBEnv(true);
            env.start();
            model = new GRBModel(env);
            model.set("OutputFlag", "0");

            // 创建决策变量
            x = model.addVars(xNum, GRB.BINARY);
            t = model.addVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "t");

            // 设置目标函数
            GRBLinExpr expr = new GRBLinExpr();
            expr.addTerms(new Matrix(1, xNum, 7).getArray()[0], x);
            expr.addTerm(1, t);
            model.setObjective(expr, GRB.MINIMIZE);
        } catch (GRBException e) {
            System.out.println("Error code: " + e.getErrorCode() + ". " + e.getMessage());
        }
    }

    private void addCut(Matrix vector, String name) {
        double constant = vector.getMatrix(0, 2, 0, 0).transpose().times(new Matrix(new double[] { 8, 3, 5 }, 3))
                .get(0, 0);
        double[] coeff = new double[5];
        for (int i = 0; i < coeff.length; i++) {
            coeff[i] = vector.get(i + 3, 0) * new double[] { 8, 3, 5, 5, 3 }[i];
        }

        try {
            GRBLinExpr expr = new GRBLinExpr();
            expr.addTerms(coeff, x);
            if (name == "Optimality Cut") {
                expr.addTerm(-1, t);
            }
            expr.addConstant(constant);
            model.addConstr(expr, GRB.LESS_EQUAL, 0, name);
        } catch (GRBException e) {
            System.out.println("Error code: " + e.getErrorCode() + ". " + e.getMessage());
        }
    }

    public void addFeasibilityCut(Matrix extremeRay) {
        addCut(extremeRay, "Feasibility Cut");
    }

    public void addOptimalityCut(Matrix extremePoint) {
        addCut(extremePoint, "Optimality Cut");
    }

    public void solve() {
        try {

            // 求解模型
            model.optimize();

            // 存储决策变量的值
            objVal = model.get(GRB.DoubleAttr.ObjVal);
            solutions = new Matrix(xNum, 1, 0);
            for (int i = 0; i < xNum; i++) {
                solutions.set(i, 0, model.getVars()[i].get(GRB.DoubleAttr.X));
            }
            tValue = t.get(GRB.DoubleAttr.X);

        } catch (GRBException e) {
            System.out.println("Error code: " + e.getErrorCode() + ". " + e.getMessage());
        }
    }
}
